如何用不到两千块大幅度提升QMQ性能
相比机械硬盘,SSD无论在延时和吞吐量上都具备压倒性优势,并且在随机读写时表现也很优异。但是基于成本考虑,我们在实际部署MQ时并没用采用SSD(主要是因为穷),目前SSD的成本基本上和容量成正比,企业级SSD差不多是万元/每T,为了保留3天的消息(3天也是在跟业务不断地PK的保守策略),单台就需要几十T的存储容量,如果有个几十台机器的集群,加上主从,那么光配置SSD就需要接近千万的成本。
有什么办法能获得SSD带来的硬件红利,又能节约成本呢?分析MQ的存储模型可知,需要存储大量数据的原因是有些消息会滞后消费,比如部分消息会有突发流量,在一段时间内发送大量的消息,然后慢慢消费;还有一些甚至是错峰消费,比如在白天发送消息,但是消费者并不立即消费,而是在凌晨业务低谷消费消息;另外为了应对故障处理等,有的时候消费者需要停止消费修复一些bug或故障,在修复后需要继续消费。这些滞后消费的消息往往对端到端延时并不care,但是大部分消息还是会及时的消费掉消息的。
这种存储模式是不是很熟悉?及时消费掉的消息相当于热数据,而滞后消费的消息相当于冷数据。对于冷热数据的处理我们已经有很多经验了,那就是使用分层存储。也就是对于热数据我们可以放到性能更好的存储设备上,而冷数据放在成本低,容量大的存储设备上。
那么如何实现这种方式呢,首先看看当前MQ的存储模式:
这个问题的关键是读和写都在同一个log上,无法解耦。我们只能要么全部使用SSD,要么全部使用机械硬盘。
但是我们只需要对读和写进行解耦,即可让接收消息的性能(吞吐量和延时)大幅度提升:
消息生产者发送消息到Server后,首先进入SSD,这样消息落到SSD之后Server就可以回复生产者消息接收成功,然后我们再将SSD上的消息转移到HDD上,而HDD上的消息提供读服务。这样提供收消息的存储和提供消费的存储就解耦了,这样一来,使用一个很小容量的SSD即可满足需求(比如Intel P3700 100G SSD,成本不到两千块)。
使用SSD来存储接收的消息不仅能提升消息接收消息的吞吐量和降低延时。企业级SSD往往具备很好的断电保护能力,在主机断电后SSD上的电容放电,仍然能够确保写入到SSD缓冲里的数据最终落地。有了这种保护能力,那么写入到SSD缓存基本上就可以确认数据安全了,这样一来对IO的sync性能也有很大的帮助,大部分MQ在开启了消息sync的机制后性能就会急剧下降,就是因为刷盘的成本太高。
到现在为止,我们基本上实现了通过引入小容量低成本的SSD大幅度提升消息接收能力。但是这就够了吗?
为了支撑更多的消息主题(如果每个消息主题一个或多个log文件,大量的消息主题将产生大量的log,导致整体大量的随机读写),我们将所有主题的消息合并到同一个log文件中,这样导致在同一个log文件中来自不同主题的消息会混合在一起,相同主题的消息并不连续,这个在消息未堆积的时候问题并不大,而在消息堆积的时候,因为消息不连续产生大量的随机读,并且IO的预读机制并不会仅仅读取指定大量的数据,不连续会导致读取大量并不需要的数据(其他主题的消息),这些数据都会进入page cache,大量的page cache被无用的数据白白浪费了(如下图所示,不同颜色的方块表示来自不同主题的消息):
那么我们如何让相同主题的消息连续呢?其实在将SSD的数据“转移“到机械硬盘的时候,我们是可以有所动作,并不仅仅是直接无修改的转移,我们在内存中记录每个主题每条消息在log中的位置,在转移过程中按照内存中的记录进行重写,这样我们就得到一个经过排序后的log:
经过排序后,随机IO明显减少了。